/* 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.oyrm.kobo.postproc.utils;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.oyrm.kobo.postproc.constants.Constants;
import org.oyrm.kobo.postproc.data.SurveyRecord;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * DomUtils provides the means to read in survey xml files and generate SurveyRecords
 * @author Gary Hendrick
 *
 */
public final class DomUtils {
	private static Logger logger = Logger.getLogger("org.oyrm.kobo");
	private static FileHandler lh;
	private static Formatter lf;
	static {
		try {
			lh = new FileHandler(System.getProperty("user.home")
					+ File.separator + Constants.CONFIG_STORAGEDIR
					+ File.separator + "kobo.log", true);
			lf = new SimpleFormatter();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		lh.setFormatter(lf);
		logger.addHandler(lh);
		logger.setLevel(Level.parse(System.getProperty(Constants.PROPKEY_LOGGING_LEVEL)));
	}

	public static Document createDocument(File docFile) throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		Document doc;
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			doc = builder.parse(docFile);
		} catch (SAXParseException spe) {
			// Error generated by the parser
			logger.warning("Parsing error"
					+ ", line " + spe.getLineNumber()
					+ ", uri " + spe.getSystemId());
			logger.warning(spe.getMessage() );

			// Use the contained exception, if any
			Exception  x = spe;
			if (spe.getException() != null)
				x = spe.getException();
			logger.warning(Arrays.asList(x.getStackTrace()).toString());
			throw spe;
		} catch (SAXException sxe) {
			// Error generated during parsing
			Exception  x = sxe;
			if (sxe.getException() != null)
				x = sxe.getException();
			logger.warning(Arrays.asList(x.getStackTrace()).toString());
			throw sxe;
		} catch (ParserConfigurationException pce) {
			// Parser with specified options can't be built
			logger.warning(Arrays.asList(pce.getStackTrace()).toString());
			throw pce;
		} catch (IOException ioe) {
			// I/O error
			logger.warning(Arrays.asList(ioe.getStackTrace()).toString());
			throw ioe;
		}
		return doc;
	}
	
	public static Node findSubNode(String name, Node node) {
		if (node.getNodeType() != Node.ELEMENT_NODE) {
			return null;
		}
		if (! node.hasChildNodes()) return null;

		NodeList list = node.getChildNodes();
		for (int i=0; i < list.getLength(); i++) {
			Node subnode = list.item(i);
			if (subnode.getNodeType() == Node.ELEMENT_NODE) {
				if (subnode.getNodeName().equals(name)) return subnode;
			}
		}
		return null;
	}
	
	public static SurveyRecord documentToSurveyRecord(Document doc) {
		Node node = doc.getDocumentElement();
		if(node == null) 
			return null;
		if (node.getNodeType() != Node.ELEMENT_NODE) {
			return null;
		}
		if (! node.hasChildNodes()) return null;

		SurveyRecord record = new SurveyRecord();
		
		record.setInstance(node.getNodeName());
		NodeList list = node.getChildNodes();
		
		/**
		 * TODO: Here is the location at which repeats and groups
		 * would be added. The record's answer will be recorded
		 * under the grouping.
		 * 
		 * An example of grouped data
		 * <mygroup>
		 * 	<groupedtext1>A</groupedtext1>
		 * 	<groupedtext2>B</groupedtext2>
		 * 	<groupedtext3>C</groupedtext3>
		 * </mygroup>
		 * In the future check into nested repeating and grouping
		 */
		
		for (int i=0; i < list.getLength(); i++) {
			Node subnode = list.item(i);
			if (subnode.getNodeType() == Node.ELEMENT_NODE) {
				
				//Determine if the node is a multi select node
				// Condition 1 : endsWith(Constants.MULTI_TAG)
				if(subnode.getNodeName().endsWith(Constants.MULTI_TAG)) {
					//Process the answer, if it is a Multi Select
					// Condition 2 : answers must not themselves contain any spaces
					for (String selection : subnode.getTextContent().split(" ")) {
						if(selection.isEmpty()) break;
						record.setAnswer(subnode.getNodeName()+selection, "1");
					}
				} else {
					record.setAnswer(subnode.getNodeName(), subnode.getTextContent()); 
				}
			}
		}
		return record;
	}
}
